package com.gec.anan.order.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gec.anan.common.constant.RedisConstant;
import com.gec.anan.common.execption.AnanException;
import com.gec.anan.common.result.ResultCodeEnum;
import com.gec.anan.model.entity.order.*;
import com.gec.anan.model.enums.OrderStatus;
import com.gec.anan.model.form.order.OrderInfoForm;
import com.gec.anan.model.form.order.StartDriveForm;
import com.gec.anan.model.form.order.UpdateOrderBillForm;
import com.gec.anan.model.form.order.UpdateOrderCartForm;
import com.gec.anan.model.vo.base.PageVo;
import com.gec.anan.model.vo.order.*;
import com.gec.anan.order.mapper.OrderBillMapper;
import com.gec.anan.order.mapper.OrderInfoMapper;
import com.gec.anan.order.mapper.OrderProfitsharingMapper;
import com.gec.anan.order.mapper.OrderStatusLogMapper;
import com.gec.anan.order.service.OrderInfoService;
import com.gec.anan.order.service.OrderMonitorService;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBlockingQueue;
import org.redisson.api.RDelayedQueue;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Date;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
@SuppressWarnings({"unchecked", "rawtypes"})
public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo> implements OrderInfoService {

    @Autowired
    private OrderInfoMapper orderInfoMapper;

    @Autowired
    private OrderStatusLogMapper orderStatusLogMapper;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private RedissonClient redissonClient;
    @Autowired
    private OrderMonitorService orderMonitorService;

    @Autowired
    private OrderBillMapper orderBillMapper;

    @Autowired
    private OrderProfitsharingMapper orderProfitsharingMapper;


    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean updateCouponAmount(Long orderId, BigDecimal couponAmount) {
        int row = orderBillMapper.updateCouponAmount(orderId, couponAmount);
        if (row != 1) {
            throw new AnanException(ResultCodeEnum.UPDATE_ERROR);
        }
        return true;
    }

    /**
     * 返回订单id，乘客下单
     *
     * @param orderInfoForm
     * @return
     */

    @Override
    public Long saveOrderInfo(OrderInfoForm orderInfoForm) {
        //封装到OrderInfo对象
        log.info("订单参数{}", orderInfoForm);
        OrderInfo orderInfo = new OrderInfo();
        BeanUtils.copyProperties(orderInfoForm, orderInfo);
        //创建唯一的订单id
        String orderNo = UUID.randomUUID().toString().replaceAll("-", "");
        orderInfo.setOrderNo(orderNo);
        orderInfoMapper.insert(orderInfo);
        //生成订单后，放入延迟队列
        sendDelayMessage(orderInfo.getId());
        //记录日志
        log(orderInfo.getId(), orderInfo.getStatus());
        //redis存放接单状态标识 与司机抢单使用
        redisTemplate.opsForValue().set(RedisConstant.ORDER_ACCEPT_MARK + orderInfo.getId().toString()
                , "0", RedisConstant.ORDER_ACCEPT_MARK_EXPIRES_TIME, TimeUnit.MINUTES);
        return orderInfo.getId();
    }

    //redisson实现取消超时订单
    private void sendDelayMessage(Long orderId) {
        try {
            //创建队列
            RBlockingQueue<Object> blockingQueue = redissonClient.getBlockingQueue("queue-cancel");
            //创建临时队列
            RDelayedQueue<Object> delayedQueue = redissonClient.getDelayedQueue(blockingQueue);
            //将消息放入延迟队列 设置过期时间
            delayedQueue.offer(orderId.toString(), 15, TimeUnit.MINUTES);
        } catch (Exception e) {
            e.printStackTrace();
            throw new AnanException(ResultCodeEnum.DATA_ERROR);
        }

    }

    /**
     * 获取订单状态
     *
     * @param orderId
     * @return
     */
    @Override
    public Integer getOrderStatus(Long orderId) {
        //查询数据库订单信息
        OrderInfo orderInfo = orderInfoMapper.selectOne(new LambdaQueryWrapper<OrderInfo>()
                .eq(OrderInfo::getId, orderId)
                .select(OrderInfo::getStatus));
        //判断
        if (orderInfo == null) {
            return OrderStatus.NULL_ORDER.getStatus();
        }
        return orderInfo.getStatus();
    }

    /**
     * 抢单功能
     *
     * @param driverId
     * @param orderId
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean robNewOrder(Long driverId, Long orderId) {
        //判断订单是否存在 redis
        if (!redisTemplate.hasKey(RedisConstant.ORDER_ACCEPT_MARK + orderId.toString())) {
            throw new AnanException(ResultCodeEnum.COB_NEW_ORDER_FAIL);
        }

        //创建锁
        RLock lock = redissonClient.getLock(RedisConstant.ROB_NEW_ORDER_LOCK + orderId);
        try {
            //获取锁
            boolean flag = lock.tryLock(RedisConstant.COUPON_LOCK_WAIT_TIME, RedisConstant.COUPON_LOCK_LEASE_TIME, TimeUnit.SECONDS);
            //防止重复抢单
            if (flag) {
                if (!redisTemplate.hasKey(RedisConstant.ORDER_ACCEPT_MARK + orderId.toString())) {
                    throw new AnanException(ResultCodeEnum.COB_NEW_ORDER_FAIL);
                }
                //基于乐观锁来实现防止超卖
                //LambdaQueryWrapper<OrderInfo> queryWrapper = new LambdaQueryWrapper<>();
                //queryWrapper.eq(OrderInfo::getId, orderId);
                //queryWrapper.eq(OrderInfo::getStatus,OrderStatus.WAITING_ACCEPT.getStatus());
                // OrderInfo orderInfo1 = new OrderInfo();
                // orderInfo1.setStatus(OrderStatus.WAITING_ACCEPT.getStatus());
                // orderInfo1.setDriverId(driverId);
                //orderInfo1.setAcceptTime(new Date());
                //orderInfoMapper.update(orderInfo1, queryWrapper);

                //存在就查询订单信息
                LambdaQueryWrapper<OrderInfo> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(OrderInfo::getId, orderId);
                OrderInfo orderInfo = orderInfoMapper.selectOne(queryWrapper);
                //修改订单信息
                orderInfo.setDriverId(driverId);
                orderInfo.setAcceptTime(new Date());
                orderInfo.setStatus(OrderStatus.ACCEPTED.getStatus());
                int rows = orderInfoMapper.updateById(orderInfo);
                if (rows != 1) {
                    throw new AnanException(ResultCodeEnum.COB_NEW_ORDER_FAIL);
                }
                //记录日志
                log(orderId, orderInfo.getStatus());

                //删除redis标识
                redisTemplate.delete(RedisConstant.ORDER_ACCEPT_MARK + orderId.toString());
            }
        } catch (Exception e) {
            throw new AnanException(ResultCodeEnum.COB_NEW_ORDER_FAIL);
        } finally {
            if (lock.isLocked()) {
                lock.unlock();
            }
        }
        return true;
    }

    //乘客端查询当前订单
    @Override
    public CurrentOrderInfoVo searchCustomerCurrentOrder(Long customerId) {
        //获取乘客id
        LambdaQueryWrapper<OrderInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(OrderInfo::getCustomerId, customerId);
        //建立订单状态
        //乘客端支付完订单，乘客端主要流程就走完（当前这些节点，乘客端会调整到相应的页面处理逻辑）
        Integer[] statusArray = {
                OrderStatus.ACCEPTED.getStatus(),
                OrderStatus.DRIVER_ARRIVED.getStatus(),
                OrderStatus.UPDATE_CART_INFO.getStatus(),
                OrderStatus.START_SERVICE.getStatus(),
                OrderStatus.END_SERVICE.getStatus(),
                OrderStatus.UNPAID.getStatus()
        };
        queryWrapper.in(OrderInfo::getStatus, statusArray);
        //排序与获取最新一条记录
        queryWrapper.orderByDesc(OrderInfo::getId);
        queryWrapper.last("limit 1");
        OrderInfo orderInfo = orderInfoMapper.selectOne(queryWrapper);
        CurrentOrderInfoVo currentOrderInfoVo = new CurrentOrderInfoVo();
        if (orderInfo != null) {
            currentOrderInfoVo.setOrderId(orderInfo.getId());
            currentOrderInfoVo.setStatus(orderInfo.getStatus());
            currentOrderInfoVo.setIsHasCurrentOrder(true);
        } else {
            currentOrderInfoVo.setIsHasCurrentOrder(false);
        }
        return currentOrderInfoVo;
    }

    //司机查找当前订单
    @Override
    public CurrentOrderInfoVo searchDriverCurrentOrder(Long driverId) {
        LambdaQueryWrapper<OrderInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(OrderInfo::getDriverId, driverId);
        //建立订单状态
        //乘客端支付完订单，乘客端主要流程就走完（当前这些节点，乘客端会调整到相应的页面处理逻辑）
        Integer[] statusArray = {
                OrderStatus.ACCEPTED.getStatus(),
                OrderStatus.DRIVER_ARRIVED.getStatus(),
                OrderStatus.UPDATE_CART_INFO.getStatus(),
                OrderStatus.START_SERVICE.getStatus(),
                OrderStatus.END_SERVICE.getStatus(),
                OrderStatus.UNPAID.getStatus()
        };
        queryWrapper.in(OrderInfo::getStatus, statusArray);
        queryWrapper.orderByDesc(OrderInfo::getId);
        queryWrapper.last("limit 1");
        OrderInfo orderInfo = orderInfoMapper.selectOne(queryWrapper);
        CurrentOrderInfoVo currentOrderInfoVo = new CurrentOrderInfoVo();
        if (orderInfo != null) {
            currentOrderInfoVo.setOrderId(orderInfo.getId());
            currentOrderInfoVo.setStatus(orderInfo.getStatus());
            currentOrderInfoVo.setIsHasCurrentOrder(true);
        } else {
            currentOrderInfoVo.setIsHasCurrentOrder(false);
        }
        return currentOrderInfoVo;
    }

    //司机到达乘客位置
    @Override
    public Boolean driverArriveStartLocation(Long orderId, Long driverId) {
        LambdaQueryWrapper<OrderInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(OrderInfo::getDriverId, driverId);
        queryWrapper.eq(OrderInfo::getId, orderId);
        //修改订单信息
        OrderInfo orderInfo = new OrderInfo();
        orderInfo.setArriveTime(new Date());
        orderInfo.setStatus(OrderStatus.DRIVER_ARRIVED.getStatus());
        int i = orderInfoMapper.update(orderInfo, queryWrapper);
        if (i == 1) {
            log(orderId, orderInfo.getStatus());
        } else {
            throw new AnanException(ResultCodeEnum.UPDATE_ERROR);
        }
        return true;
    }

    //更新订单车辆信息
    @Override
    public Boolean updateOrderCart(UpdateOrderCartForm updateOrderCartForm) {
        LambdaQueryWrapper<OrderInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(OrderInfo::getDriverId, updateOrderCartForm.getDriverId());
        queryWrapper.eq(OrderInfo::getId, updateOrderCartForm.getOrderId());
        //更新车辆信息
        OrderInfo orderInfo = new OrderInfo();
        BeanUtils.copyProperties(updateOrderCartForm, orderInfo);
        orderInfo.setStatus(OrderStatus.UPDATE_CART_INFO.getStatus());
        int i = orderInfoMapper.update(orderInfo, queryWrapper);
        if (i == 1) {
            log(updateOrderCartForm.getOrderId(), orderInfo.getStatus());
        } else {
            throw new AnanException(ResultCodeEnum.UPDATE_ERROR);
        }
        System.out.println("更新车辆信息");
        return true;
    }

    //开始代驾
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean startDrive(StartDriveForm startDriveForm) {
        LambdaQueryWrapper<OrderInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(OrderInfo::getDriverId, startDriveForm.getDriverId());
        queryWrapper.eq(OrderInfo::getId, startDriveForm.getOrderId());
        //修改的数据
        OrderInfo orderInfo = new OrderInfo();
        orderInfo.setStatus(OrderStatus.START_SERVICE.getStatus());
        orderInfo.setStartServiceTime(new Date());
        int i = orderInfoMapper.update(orderInfo, queryWrapper);
        if (i == 1) {
            log(startDriveForm.getOrderId(), orderInfo.getStatus());
        } else {
            throw new AnanException(ResultCodeEnum.UPDATE_ERROR);
        }
        //初始化订单监控统计数据
        OrderMonitor orderMonitor = new OrderMonitor();
        orderMonitor.setOrderId(startDriveForm.getOrderId());
        orderMonitorService.saveOrderMonitor(orderMonitor);
        return true;
    }

    //根据时间段查询订单数量
    @Override
    public Long getOrderNumByTime(String startTime, String endTime) {
        //封装查询条件
        LambdaQueryWrapper<OrderInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.ge(OrderInfo::getStartServiceTime, startTime);
        queryWrapper.lt(OrderInfo::getStartServiceTime, endTime);
        Long count = orderInfoMapper.selectCount(queryWrapper);
        return count;
    }

    //结束代驾，更新账单
    @Override
    public Boolean endDrive(UpdateOrderBillForm updateOrderBillForm) {
        log.info("结束代驾，更新账单{}", updateOrderBillForm);
        //封装条件，更新数据表
        LambdaQueryWrapper<OrderInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(OrderInfo::getDriverId, updateOrderBillForm.getDriverId());
        queryWrapper.eq(OrderInfo::getId, updateOrderBillForm.getOrderId());
        //更新内容
        OrderInfo orderInfo = new OrderInfo();
        orderInfo.setEndServiceTime(new Date());
        orderInfo.setStatus(OrderStatus.END_SERVICE.getStatus());
        orderInfo.setFavourFee(updateOrderBillForm.getFavourFee());
        orderInfo.setRealAmount(updateOrderBillForm.getTotalAmount());
        orderInfo.setRealDistance(updateOrderBillForm.getRealDistance());
        //更新
        int i = orderInfoMapper.update(orderInfo, queryWrapper);
        if (i == 1) {
            //添加日志
            log(updateOrderBillForm.getOrderId(), orderInfo.getStatus());
            //添加实际账单信息
            OrderBill orderBill = new OrderBill();
            BeanUtils.copyProperties(updateOrderBillForm, orderBill);
            orderBill.setOrderId(updateOrderBillForm.getOrderId());
            orderBill.setPayAmount(orderBill.getTotalAmount());
            orderBillMapper.insert(orderBill);

            //添加系统分账信息
            OrderProfitsharing orderProfitsharing = new OrderProfitsharing();
            BeanUtils.copyProperties(updateOrderBillForm, orderProfitsharing);
            orderProfitsharing.setOrderId(updateOrderBillForm.getOrderId());
            orderProfitsharing.setRuleId(updateOrderBillForm.getProfitsharingRuleId()==null?0:updateOrderBillForm.getProfitsharingRuleId());
            orderProfitsharing.setStatus(1);
            int insert = orderProfitsharingMapper.insert(orderProfitsharing);
            log.info("分账信息{}", insert);
        } else {
            throw new AnanException(ResultCodeEnum.UPDATE_ERROR);
        }
        return true;
    }

    //    获取乘客订单分页列表
    @Override
    public PageVo findCustomerOrderPage(Page<OrderInfo> pageParam, Long customerId) {
        IPage<OrderListVo> iPage = orderInfoMapper.selectCustomerOrderPage(pageParam, customerId);
        return new PageVo(iPage.getRecords(), iPage.getPages(), iPage.getTotal());
    }

    //根据司机id查找订单列表
    @Override
    public PageVo findDriverOrderPage(Page<OrderInfo> pageParam, Long driverId) {
        IPage<OrderListVo> iPage = orderInfoMapper.selectDriverOrderPage(pageParam, driverId);
        return new PageVo(iPage.getRecords(), iPage.getPages(), iPage.getTotal());
    }

    //根据订单id获取实际账单信息
    @Override
    public OrderBillVo getOrderBillInfo(Long orderId) {
        LambdaQueryWrapper<OrderBill> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(OrderBill::getOrderId, orderId);
        OrderBill orderBill = orderBillMapper.selectOne(queryWrapper);
        OrderBillVo orderBillVo = new OrderBillVo();
        BeanUtils.copyProperties(orderBill, orderBillVo);
        return orderBillVo;
    }

    //根据订单id获取实际分账信息
    @Override
    public OrderProfitsharingVo getOrderProfitsharing(Long orderId) {
        LambdaQueryWrapper<OrderProfitsharing> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(OrderProfitsharing::getOrderId, orderId);
        OrderProfitsharing orderProfitsharing = orderProfitsharingMapper.selectOne(queryWrapper);
        OrderProfitsharingVo orderProfitsharingVo = new OrderProfitsharingVo();
        BeanUtils.copyProperties(orderProfitsharing, orderProfitsharingVo);
        return orderProfitsharingVo;
    }

    //司机推送支付订单
    @Override
    public Boolean sendOrderBillInfo(Long orderId, Long driverId) {
        //更新订单信息
        LambdaQueryWrapper<OrderInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(OrderInfo::getId, orderId);
        queryWrapper.eq(OrderInfo::getDriverId, driverId);
        //更新字段
        OrderInfo updateOrderInfo = new OrderInfo();
        updateOrderInfo.setStatus(OrderStatus.UNPAID.getStatus());
        //只能更新自己的订单
        int row = orderInfoMapper.update(updateOrderInfo, queryWrapper);
        if (row == 1) {
            //记录日志
            this.log(orderId, OrderStatus.UNPAID.getStatus());
        } else {
            throw new AnanException(ResultCodeEnum.UPDATE_ERROR);
        }
        return true;
    }

    //获取订单支付信息
    @Override
    public OrderPayVo getOrderPayVo(String orderNo, Long customerId) {
        OrderPayVo orderPayVo = orderInfoMapper.getOrderPayVo(orderNo, customerId);
        if (orderPayVo != null) {
            String content = orderPayVo.getStartLocation() + " 到 " + orderPayVo.getEndLocation();
            orderPayVo.setContent(content);
        }
        return orderPayVo;
    }

    //修改订单状态
    @Override
    public Boolean updateOrderPayStatus(String orderNo) {
        //根据订单号查询订单
        LambdaQueryWrapper<OrderInfo> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(OrderInfo::getOrderNo, orderNo);
        OrderInfo orderInfo = orderInfoMapper.selectOne(queryWrapper);
        //判断订单是否需要修改
        if (null == orderInfo && orderInfo.getStatus().intValue() == OrderStatus.PAID.getStatus().intValue()) {
            return true;
        }
        //更新订单状态
        LambdaQueryWrapper<OrderInfo> updateQueryWrapper = new LambdaQueryWrapper<>();
        updateQueryWrapper.eq(OrderInfo::getOrderNo, orderNo);
        //修改订单状态
        OrderInfo info = new OrderInfo();
        info.setStatus(OrderStatus.PAID.getStatus());
        info.setPayTime(new Date());
        int row = orderInfoMapper.update(info, updateQueryWrapper);
        if (row == 1) {
            log(orderInfo.getId(), OrderStatus.PAID.getStatus());
        } else {
            throw new AnanException(ResultCodeEnum.UPDATE_ERROR);
        }
        return true;
    }

    @Override
    public OrderRewardVo getOrderRewardFee(String orderNo) {
        //查询orderInfo获得司机订单id
        OrderInfo orderInfo = orderInfoMapper.selectOne(new LambdaQueryWrapper<OrderInfo>()
                .eq(OrderInfo::getOrderNo, orderNo)
                .select(OrderInfo::getDriverId, OrderInfo::getId));
        //查询orderBill获得系统奖励
        OrderBill orderBill = orderBillMapper.selectOne(new LambdaQueryWrapper<OrderBill>()
                .eq(OrderBill::getOrderId, orderInfo.getId())
                .select(OrderBill::getRewardFee));
        //封装vo
        OrderRewardVo orderRewardVo = new OrderRewardVo();
        orderRewardVo.setOrderId(orderInfo.getId());
        orderRewardVo.setRewardFee(orderBill.getRewardFee());
        orderRewardVo.setDriverId(orderInfo.getDriverId());
        return orderRewardVo;
    }

    //订单取消
    @Override
    public void orderCancel(long orderId) {
        //查询订单信息
        OrderInfo orderInfo = orderInfoMapper.selectById(orderId);
        if (orderInfo.getStatus() == OrderStatus.WAITING_ACCEPT.getStatus()) {
            //修改订单状态
            orderInfo.setStatus(OrderStatus.CANCEL_ORDER.getStatus());
            int i = orderInfoMapper.updateById(orderInfo);
            log.info("订单取消，订单号：{}+是否成功{}" ,orderInfo.getOrderNo(),i);
            if (i == 1) {
                //删除接单标识redis
                redisTemplate.delete(RedisConstant.ORDER_ACCEPT_MARK + orderInfo.getId().toString());
                 log.info("订单取消成功");
            }
        }
    }

    //记录日志的方法
    private void log(Long orderId, Integer status) {
        OrderStatusLog orderStatusLog = new OrderStatusLog();
        orderStatusLog.setOrderId(orderId);
        orderStatusLog.setOrderStatus(status);
        orderStatusLog.setOperateTime(new Date());
        orderStatusLogMapper.insert(orderStatusLog);
    }

}
